import 'dart:async';
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:logger/logger.dart';
import 'package:ball_lion/entity/live/live_detail_entity.dart';
import 'package:ball_lion/entity/live/ali_live_message.dart';
import 'package:ball_lion/server/ws/ali_im_manager.dart';
import 'package:ball_lion/utils/ali_message.dart';
import 'package:ball_lion/utils/gift_cache.dart';
import 'package:ball_lion/utils/toast_utils.dart';
import 'package:ball_lion/utils/utils.dart';
import 'package:ball_lion/module/live/items/gift_effect_view.dart';
import 'package:ball_lion/widgets/base/wqs_dialog.dart';
import 'package:ball_lion/entity/live/live_chat_entity.dart';
import 'package:ball_lion/entity/live/live_chat_info.dart';
import 'package:ball_lion/entity/match/expert_views_entity.dart';
import 'package:ball_lion/entity/other/user_info_entity.dart';
import 'package:ball_lion/resources/colours.dart';
import 'package:ball_lion/server/api/expert_api.dart';
import 'package:ball_lion/server/api/live_api.dart';
import 'package:ball_lion/server/api/user_api.dart';
import 'package:ball_lion/utils/user.dart';
import 'package:ball_lion/utils/widget_utils.dart';
import 'package:ball_lion/module/live/items/live_message_list.dart';
import 'package:ball_lion/widgets/circular.dart';
import 'package:ball_lion/widgets/base/wqs_image.dart';
import 'package:ball_lion/widgets/base/wqs_text.dart';
import 'package:ball_lion/widgets/slide_transition_x.dart';
import 'package:ball_lion/widgets/player/qs_player_logic.dart';

class LiveMessageLogic extends GetxController {
  LiveMessageLogic({required this.liveDetail, required this.scene});
  final MessageScene scene;
  LiveDetailEntity? liveDetail;
  LiveChatInfo? chatInfo;
  PlanEntity? plan;
  bool _showPlan = true;
  ScrollController scrollController = ScrollController();
  List<AliLiveMessage> messages = [];
  bool _inScroll = false;
  int _messageCount = 0;
  bool _showMessage = false;
  final Rx<String> _str = "".obs;
  final textController = TextEditingController();
  late FocusNode focus = FocusNode();
  UserInfoEntity? _userStore;
  List<AliLiveMessage> gifts = [];
  GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
  Timer? _giftTimer;
  bool _coverJoin = true;
  Timer? _joinTimer;

  bool get inScroll => _inScroll;
  int get messageCount => _messageCount;
  bool get showMessage => _showMessage;
  String get str => _str.value;
  bool get showPlan => _showPlan;
  UserInfoEntity? get userStore => _userStore;
  bool get coverJoin => _coverJoin;

  set coverJoin(bool value) {
    _coverJoin = value;
    update();
  }

  set userStore(UserInfoEntity? value) {
    _userStore = value;
    update();
  }

  set showPlan(bool value) {
    _showPlan = value;
    update();
  }

  set str(String value) {
    _str.value = value;
  }

  set showMessage(bool value) {
    _showMessage = value;
    if (value == false) messageCount = 0;
    update();
  }

  set messageCount(int value) {
    _messageCount = value;
    update();
  }

  set inScroll(bool value) {
    _inScroll = value;
    update();
  }

  @override
  void onInit() {
    AliMessage().enterGroup(liveDetail?.chatGroupId ?? "");
    _giftTimer = Timer.periodic(const Duration(seconds: 1), (timer) async {
      for (int i = 0; i < gifts.length; i++) {
        if (gifts[i].showTime != null) {
          if (DateTime.now().difference(gifts[i].showTime!).inSeconds > 4) {
            removeGift(i);
          }
        }
      }
    });
    focus.addListener(() {
      if (focus.hasFocus) {
        update();
      }
      if (!focus.hasFocus) {
        update();
      }
    });
    super.onInit();
  }

  @override
  void onReady() async {
    await getInfo();
    await getHistory();
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      scrollToEnd();
    });
    AliMessage().messageResp().listen((event) async {
      AliLiveMessage? message;
      try {
        message = AliLiveMessage.fromJson(jsonDecode(event));
        AliImManager.recordAdd("收到消息:${message.toJson()}");
      } catch (e) {
        Logger().d(e);
        AliImManager.recordAdd("收到消息 error:${e}");
      }
      if (message == null) return;
      switch (message.status) {
        case MessageType.joinGroup:
          if (message.userName.hasValue) {
            coverJoin = false;
            if (!coverJoin) _joinTimer?.cancel();
            _joinTimer =
                Timer(const Duration(seconds: 5), () => coverJoin = true);
            if (messages.last.status == MessageType.joinGroup) {
              messages.last = message;
            } else {
              messages.add(message);
            }
          }
          break;
        case MessageType.sendMessage:
          if (message.userName.hasValue) {
            handleMessage(message);
          }
          if (showMessage) messageCount += 1;
          break;
        case MessageType.gift:
          if (message.userName.hasValue) {
            handleMessage(message);
            int index = gifts.indexWhere((element) =>
                element.giftName == message?.giftName &&
                element.userId == message?.userId);
            if (index != -1) {
              gifts[index].count =
                  (gifts[index].count ?? 0) + (message.count ?? 0);
              gifts[index].showTime = DateTime.now();
            } else {
              if (gifts.length == 2) removeGift(0);
              insertGift(message);
            }
            if (message.animateUrl.hasValue) {
              try {
                String path = await GiftCache.getPath(message.animateUrl!);
                GiftEffectController().play(path);
              } catch (e) {
                Logger().d("GiftEffectError: $e");
              }
            }
            if (showMessage) messageCount += 1;
          }
          break;
        case MessageType.deleteMessage:
          messages.removeWhere(
              (element) => element.messageId == message?.messageId);
          if (showMessage) messageCount -= 1;
          break;
        case MessageType.mute:
          // TODO: Handle this case.
          break;
        case MessageType.muteAll:
          // TODO: Handle this case.
          break;
        case MessageType.cancelMute:
          // TODO: Handle this case.
          break;
        case MessageType.cancelMuteAll:
          // TODO: Handle this case.
          break;
        case MessageType.exitGroup:
          // TODO: Handle this case.
          break;
        case MessageType.announce:
          messages.add(message);
          break;
        case MessageType.focus:
          if (message.userName.hasValue) {
            handleMessage(message);
            if (showMessage) messageCount += 1;
          }
          break;
        case MessageType.other:
          handleMessage(message);
          if (showMessage) messageCount += 1;
          break;
        case MessageType.error:
          // TODO: Handle this case.
          break;
        case MessageType.completion:
          try {
            Get.find<QsPlayerLogic>(tag: "${liveDetail?.liveId}").status =
                PlayStatus.completion;
          } catch (e) {
            try {
              Get.find<QsPlayerLogic>(tag: "${liveDetail?.matchId}").status =
                  PlayStatus.completion;
            } catch (e) {
              Logger().d("complete error");
            }
            Logger().d("complete error");
          }
          break;
        default:
          break;
      }
      update();
      if (!showMessage) scrollToEnd();
    });
    super.onReady();
  }

  void handleMessage(AliLiveMessage message) {
    if (!coverJoin) {
      messages.insert(messages.length > 1 ? messages.length - 1 : 0, message);
    } else {
      if (messages.last.status == MessageType.joinGroup) {
        messages.removeLast();
      }
      messages.add(message);
    }
  }

  Future getInfo() async {
    chatInfo = await LiveApi.getChatInfo(liveDetail?.liveId);
    if (chatInfo?.noticeSystem.hasValue == true) {
      messages.add(AliLiveMessage(
          message: chatInfo?.noticeSystem, status: MessageType.announce));
    }
    if (chatInfo?.noticeRoom.hasValue == true) {
      messages.add(AliLiveMessage(
          message: chatInfo?.noticeRoom, status: MessageType.announce));
    }
    try {
      var row = await ExpertApi.getLivePlan("${liveDetail?.matchId}",
          liveDetail?.expertId, liveDetail?.sportsId ?? 1, 1, 10);
      if (row.recommend.hasValue) {
        plan = row.recommend!.first;
      }
      // else if (row.other.hasValue) {
      //   plan = row.other!.first;
      // }
    } catch (e) {
      Logger().d(e);
    }
    update();
  }

  Future getHistory() async {
    List<LiveChatEntity>? list =
        await LiveApi.getChatHistory(id: liveDetail?.liveId);
    List<AliLiveMessage>? history =
        list.map((e) => AliLiveMessage.fromChatMessage(e)).toList();
    messages.addAll(history);
    update();
  }

  Future muteUser(AliLiveMessage message) async {
    var check = await LiveApi.checkMuteUser(
        liveDetail?.liveId ?? 0, message.userId ?? "");
    var result = await Get.dialog(QsDialog.alert(
      check ?? false
          ? "确定解除${message.userName ?? ""}的禁言吗"
          : "确定禁言${message.userName ?? ""}吗",
      confirmText: check ?? false ? "解除" : "禁言",
    ));
    if (result == true) {
      var back = await LiveApi.muteUser(
          liveDetail?.liveId ?? 0, message.userId ?? "", check ?? false);
      if (back == true) {
        Toast.text("${check ?? false ? "解禁" : "禁言"}成功");
      } else {
        Toast.text("${check ?? false ? "解禁" : "禁言"}失败");
      }
    }
  }

  Future deleteMessage(AliLiveMessage message) async {
    var result = await Get.dialog(QsDialog.alert(
      "确定删除${message.userName ?? ""}的评论吗",
      confirmText: "删除",
    ));
    if (result == true) {
      var back =
          await LiveApi.deleteMessage((message.messageId ?? "").toInt() ?? 0);
      if (back == true) {
        Toast.text("删除成功");
      } else {
        Toast.text("删除失败");
      }
    }
  }

  Future sendChat({String? text}) async {
    await LiveApi.sendChat(text ?? str, liveDetail?.liveId);
  }

  @override
  void onClose() {
    AliMessage().leaveGroup(liveDetail?.chatGroupId ?? "", liveDetail?.liveId);
    _giftTimer?.cancel();
    super.onClose();
  }

  Future scrollToEnd({double? position}) async {
    if (inScroll) return;
    inScroll = true;
    await Future.delayed(const Duration(milliseconds: 200));
    await scrollController.animateTo(
        position ?? scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 200),
        curve: Curves.easeIn);
    messageCount = 0;
    inScroll = false;
    update();
  }

  Widget gift(int index, Animation<double> animation, {AliLiveMessage? msg}) {
    AliLiveMessage entity = msg ?? gifts[index];
    Color red =
        scene == MessageScene.match ? Colours.redFBAFBC : Colours.redFF748D;
    Color blue =
        scene == MessageScene.match ? Colours.blueBADDF9 : Colours.blue74C4FF;
    late Color bgColor =
        (entity.price ?? 0) * (entity.count ?? 0) >= 20 ? red : blue;
    late List<Color> colors = [
      bgColor.withOpacity(scene == MessageScene.match ? 1 : 0.8),
      bgColor.withOpacity(0)
    ];
    List<double> stops =
        scene == MessageScene.match ? [0.85, 0.98] : [0.2, 0.85];
    Color textColor =
        scene == MessageScene.match ? Colours.text : Colours.white;
    return SlideTransition(
      position:
          Tween<Offset>(begin: const Offset(-1, 0), end: const Offset(0, 0))
              .animate(animation),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Circular(
            width: 222,
            height: 36,
            margin: const EdgeInsets.only(left: 8, bottom: 4),
            borderRadius:
                const BorderRadius.horizontal(left: Radius.circular(36)),
            gradient: LinearGradient(colors: colors, stops: stops),
            child: Row(
              children: [
                Padding(
                  padding: const EdgeInsets.fromLTRB(2, 2, 0, 2),
                  child: QsImage(
                    imageUrl: entity.userAvatar ?? "",
                    width: 32,
                    height: 32,
                    shape: BoxShape.circle,
                    fit: BoxFit.cover,
                    shimmer: false,
                  ),
                ),
                Container(width: 8),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Flexible(
                        child: QsText(
                          entity.userName ?? "",
                          fontSize: 12,
                          color: textColor,
                          fontWeight: FontWeight.w500,
                          maxLines: 1,
                        ),
                      ),
                      QsText(
                        entity.message ?? "",
                        fontSize: 10,
                        color: textColor.withOpacity(0.6),
                        maxLines: 1,
                      )
                    ],
                  ),
                ),
                Container(width: 8),
                Row(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    QsImage(
                      imageUrl: entity.giftLogo ?? "",
                      width: 36,
                      height: 36,
                      fit: BoxFit.cover,
                      shimmer: false,
                    ),
                    Container(width: 3),
                    QsText("x",
                        fontSize: 17, fontFamily: "KingKong", color: textColor),
                    AnimatedSwitcher(
                        duration: const Duration(milliseconds: 150),
                        transitionBuilder: (child, animation) =>
                            SlideTransitionX(
                                position: animation,
                                direction: AxisDirection.right,
                                child: child),
                        child: QsText("${entity.count ?? 1}",
                            key: ValueKey<int>(entity.count ?? 1),
                            fontSize: 17,
                            fontFamily: "KingKong",
                            color: textColor))
                  ],
                )
              ],
            ),
          ),
        ],
      ),
    );
  }

  void removeGift(int index) {
    AliLiveMessage msg = gifts.removeAt(index);
    listKey.currentState?.removeItem(index, (context, animation) {
      return gift(index, animation, msg: msg);
    });
    update();
  }

  void insertGift(AliLiveMessage message) {
    message.showTime = DateTime.now();
    gifts.add(message);
    listKey.currentState?.insertItem(gifts.isEmpty ? 0 : gifts.length - 1);
    update();
  }

  Future toFocus() async {
    await User.needLogin(() {
      Utils.onEvent('liveroom_gift_follow');
      if (userStore?.id != User.info?.id) {
        AliMessage().enterGroup(liveDetail?.chatGroupId ?? "");
        userStore = User.info;
      }
    });
    if (liveDetail?.isFocus == 0) {
      final result = await UserApi.focus(expertId: liveDetail?.expertId);
      if (result == 200) {
        LiveDetailEntity? entity =
            await LiveApi.getLiveDetail(liveDetail?.liveId);
        if (entity != null) {
          liveDetail?.isFocus = entity.isFocus;
          Toast.text('关注成功');
        } else {
          Toast.text('关注失败');
        }
        update();
      }
    } else {
      final r = await WidgetUtils.alertQuery('确认不再关注？');
      if (r == true) {
        final result = await UserApi.unFocus(expertId: liveDetail?.expertId);
        if (result == 200) {
          LiveDetailEntity? entity =
              await LiveApi.getLiveDetail(liveDetail?.liveId);
          if (entity != null) {
            liveDetail?.isFocus = entity.isFocus;
            Toast.text('取关成功');
          } else {
            Toast.text('取关失败');
          }
          update();
        }
      }
    }
  }
}
